﻿using System;
using System.IO;
using System.Text;

namespace ConsoleApp;

/// <summary>
/// 对于文本文件的读写，可以使用StreamReader和StreamWriter类，它们提供了高效的流读取/写入功能，并且底层是通过FileStream实现读写文本文件
/// 对于二进制文件的读写，可以使用BinaryReader和BinaryWriter类，它们允许你以二进制格式读取和写入原始数据，这在处理大型或需要高效处理的数据时特别有用
/// 对于更底层的文件操作，可以使用FileStream类，它提供了对磁盘上文件的直接读写能力，并且可以通过设置缓冲区大小等参数来优化性能
/// 对于使用异步编程模型, File.ReadAllTextAsync、File.WriteAllTextAsync
/// </summary>
internal class DemoIO
{
    // 绝对路径和相对路径
    // 绝对路径：通过给定的这个路径直接能在我的电脑中找到这个文件。
    // 相对路径：文件相对于应用程序的路径。
    // 结论：我们在开发中应该去尽量的使用相对路径。
    // 将创建文件流对象的过程写在using当中，会自动的帮助我们释放流所占用的资源。


    public void Handle()
    {
        var inputPath = @"D:\input.txt";
        var outputPath = @"D:\output.txt";

        // 使用 HashSet 记录已存在的行
        var seenLines = new HashSet<string>();
        // 读取文件并去重 忽略大小写的去重（可选）：使用 line.ToLower() 或 line.ToUpper(); Trim() 可选：去除首尾空格
        var uniqueLines = File.ReadLines(inputPath).Where(line => seenLines.Add(line.Trim())).ToList();

        // 写入新文件
        var txt = new StringBuilder();
        foreach (var line in uniqueLines)
        {
            txt.Append(line + ",");
        }
        File.WriteAllText(outputPath, txt.ToString());

        //File.WriteAllLines(outputPath, uniqueLines);

        Console.WriteLine("去重完成！");
    }
    
    public static String ReadFileContent(string filePath)
    {
        var bytes = ReadBinaryFileContent(filePath);

        // 使用UTF8编码将字节数组转换为字符串
        return Encoding.UTF8.GetString(bytes);

        // 使用Unicode编码将字节数组转换为字符串
        return Encoding.Unicode.GetString(bytes);
    }

    public static byte[] ReadBinaryFileContent(string filePath)
    {
        using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
        using var reader = new BinaryReader(stream);
        var fileContent = reader.ReadBytes((int)stream.Length); // 读取整个文件的内容为字节数组

        return fileContent;
    }


    public void demo()
    {
        //File
        //Create Delete Copy Move

        //string[] contents = File.ReadAllLines(@"C:\Users\SpringRain\Desktop\抽象类特点.txt", Encoding.Default);
        //foreach (string item in contents)
        //{
        //    Console.WriteLine(item);
        //}
        //Console.ReadKey();


        //string str = File.ReadAllText("抽象类特点.txt", Encoding.Default);
        //Console.WriteLine(str);
        //Console.ReadKey();

        //File.WriteAllLines(@"C:\Users\SpringRain\Desktop\new.txt", new string[] { "aoe", "ewu" });
        //Console.WriteLine("OK");
        //Console.ReadKey();


        //File.WriteAllText(@"C:\Users\SpringRain\Desktop\new.txt", "张三李四王五赵六");
        //Console.WriteLine("OK");
        //Console.ReadKey();

        //File.AppendAllText(@"C:\Users\SpringRain\Desktop\new.txt", "看我有木有把你覆盖掉");
        //Console.WriteLine("OK");
        //Console.ReadKey();

        //BinaryReader
        //从二进制流中读取原始数据。

        //BinaryWriter
        //以二进制格式写入原始数据。

        //BufferedStream
        //一个字节流的临时存储。

        //Directory
        //有助于操纵目录结构。

        //DirectoryInfo
        //用于对目录执行操作

        //DriveInfo
        //提供驱动器的信息。

        //File
        //用于帮助操纵文件。

        //FileInfo
        //用于对文件执行操作。

        //FileStream
        //用于读取和写入文件中的任何位置。

        //MemoryStream
        //用于随机访问存储在内存中的流式数据。

        //Path
        //执行路径信息的操作。

        //StreamReader
        //用于从字节流读取字符。

        //StreamWriter
        //用于将字符写入到流中。

        //StringReader
        //用于从字符串缓冲区读取。

        //StringWriter
        //用于写入字符串缓冲区。
    }

    static string GetLatestFile(string directoryPath)
    {
        var files = Directory.GetFiles(directoryPath);
        var latestDate = DateTime.MinValue;
        string latestFile = null;

        foreach (var file in files)
        {
            var lastWriteTime = File.GetLastWriteTime(file);
            if (lastWriteTime <= latestDate) continue;
            latestDate = lastWriteTime;
            latestFile = file;
        }

        return latestFile;
    }

    public void Test()
    {
        var path = @"D:\test.txt";
        Write(path, "demo");

        Read(path);

        //思路：就是先将要复制的多媒体文件读取出来，然后再写入到你指定的位置
        var source = @"C:\Users\SpringRain\Desktop\1、复习.wmv";
        var target = @"C:\Users\SpringRain\Desktop\new.wmv";
        Copy(source, target);
        Console.WriteLine("复制成功");
        Console.ReadKey();
    }

    public void ReadByFile(string path)
    {
        var buffer = File.ReadAllBytes(path);
        //将字节数组中的每一个元素都要按照我们指定的编码格式解码成字符串
        //UTF-8 GB2312 GBK ASCII Unicode
        var s = Encoding.Default.GetString(buffer);

        Console.WriteLine(s);
        Console.ReadKey();
    }

    public void WriteByFile(string path, string value)
    {
        //没有这个文件的话 会给你创建一个 有的话 会给你覆盖掉
        //需要将字符串转换成字节数组
        var buffer = Encoding.Default.GetBytes(value);
        File.WriteAllBytes(path, buffer);
        Console.WriteLine("写入成功");
        Console.ReadKey();
    }

    public void Write(string path, string value)
    {
        //使用FileStream来写入数据
        using var fsWrite = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write);
        var buffer = Encoding.UTF8.GetBytes(value);
        fsWrite.Write(buffer, 0, buffer.Length);
    }

    public void Read(string path)
    {
        using var fsRead = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Read);
        var buffer = new byte[1024 * 1024 * 5];
        //本次读取实际读取到的字节数
        var r = fsRead.Read(buffer, 0, buffer.Length);

        //将字节数组中的每个元素按照我们指定的编码格式解析成字符串
        var s = Encoding.Default.GetString(buffer, 0, r);
        Console.WriteLine(s);
    }

    public static void Copy(string soucre, string target)
    {
        //1、我们创建一个负责读取的流
        using var fsRead = new FileStream(soucre, FileMode.Open, FileAccess.Read);
        //2、创建一个负责写入的流
        using var fsWrite = new FileStream(target, FileMode.OpenOrCreate, FileAccess.Write);
        var buffer = new byte[1024 * 1024 * 5];
        //因为文件可能会比较大，所以我们在读取的时候 应该通过一个循环去读取
        while (true)
        {
            //返回本次读取实际读取到的字节数
            var r = fsRead.Read(buffer, 0, buffer.Length);
            //如果返回一个0，也就意味什么都没有读取到，读取完了
            if (r == 0)
            {
                break;
            }

            fsWrite.Write(buffer, 0, r);
        }
    }

    public void Writes(string path, string value)
    {
        //使用StreamWriter来写入一个文本文件
        using var sw = new StreamWriter(path, true);
        sw.Write(value);
    }

    public void Reads(string path)
    {
        //使用StreamReader来读取一个文本文件
        using var sr = new StreamReader(path, Encoding.Default);
        while (!sr.EndOfStream)
        {
            Console.WriteLine(sr.ReadLine());
        }
    }
}